﻿namespace hedefgrup.reports.renault.calculators
{
    using hedefgrup.reports.renault;
    using hedefgrup.reports.renault.date;
    using hedefgrup.reports.renault.definitions;
    using hedefgrup.reports.renault.implementation;
    using hedefgrup.reports.renault.sorting;
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Xml;

    public class reportCalculator
    {
        private SortedList<string, reportDealerInfo> calculatedDataCache = new SortedList<string, reportDealerInfo>();
        public string name;
        private dataCache _relatedDataCache;

        internal reportCalculator(dataCache relatedDataCache)
        {
            _relatedDataCache = relatedDataCache;
        }

        private void appendCoordinatorAndAreas(List<dealerDefinition> dealersToReport)
        {
            this.appendSelectedNodesToDealerList("coordinator", dealersToReport);
            this.appendSelectedNodesToDealerList("area", dealersToReport);
        }

        private void appendNonVirtualChildren(dealerDefinition parent, List<dealerDefinition> nonVirtualChildren)
        {
            string xPath = "organization/dealer";
            if (parent.sourceNode.Attributes["override_child_query"] != null)
            {
                xPath += parent.sourceNode.Attributes["override_child_query"].Value;
            }
            else
            {
                xPath += "[@parent='" + parent.getCode() + "']";
            }

            XmlNodeList list = this.getRelatedDataCache().xmlData.DocumentElement.SelectNodes(xPath);
            foreach (XmlNode node in list)
            {
                string str = node.Attributes["type"].Value;
                if (str != null)
                {
                    if ((str != "dealer") && (str != "branch"))
                    {
                        if ((str != "connected_point") && !(str == "satellite"))
                        {
                            goto Label_0134;
                        }
                    }
                    else
                    {
                        nonVirtualChildren.Add(this.getRelatedDataCache().getDealer(node.Attributes["code"].Value));
                        this.appendNonVirtualChildren(this.getRelatedDataCache().getDealer(node.Attributes["code"].Value), nonVirtualChildren);
                        continue;
                    }
                    nonVirtualChildren.Add(this.getRelatedDataCache().getDealer(node.Attributes["code"].Value));
                    continue;
                }
            Label_0134:
                this.appendNonVirtualChildren(this.getRelatedDataCache().getDealer(node.Attributes["code"].Value), nonVirtualChildren);
            }
        }

        private void appendSelectedNodesToDealerList(string typeCode, List<dealerDefinition> dealersToReport)
        {
            this.appendSelectedNodesToDealerList(typeCode, dealersToReport, false);
        }

        private void appendSelectedNodesToDealerList(XmlNodeList selectedNodes, List<dealerDefinition> dealersToReport)
        {
            this.appendSelectedNodesToDealerList(selectedNodes, dealersToReport, false);
        }

        private void appendSelectedNodesToDealerList(string typeCode, List<dealerDefinition> dealersToReport, bool appendSatellites)
        {
            this.appendSelectedNodesToDealerList(this.selectDealers("@type='" + typeCode + "'"), dealersToReport, appendSatellites);
        }

        private void appendSelectedNodesToDealerList(XmlNodeList selectedNodes, List<dealerDefinition> dealersToReport, bool appendSatellites)
        {
            foreach (XmlNode node in selectedNodes)
            {
                dealersToReport.Add(this.getRelatedDataCache().getDealer(node.Attributes["code"].Value));
                if (appendSatellites)
                {
                    this.appendSelectedNodesToDealerList(this.selectDealers("@type='satellite' and @parent='" + node.Attributes["code"].Value + "'"), dealersToReport);
                }
            }
        }

        public virtual void clearCache()
        {
            lock (this.calculatedDataCache)
            {
                this.calculatedDataCache.Clear();
            }
        }

        public virtual reportDealerInfo[] generateReportDataForMultipleDealers(calculatorType calculationType, reportMonth startMonth, reportMonth endMonth)
        {
            return this.generateReportDataForMultipleDealers(null, calculationType, startMonth, endMonth);
        }

        public virtual reportDealerInfo[] generateReportDataForMultipleDealers(dealerDefinition dealer, calculatorType calculationType, reportMonth startMonth, reportMonth endMonth)
        {
            List<dealerDefinition> dealersToReport = new List<dealerDefinition>();
            switch (calculationType)
            {
                case calculatorType.dealersAndSatellitesJoined:
                case calculatorType.dealersAndSatellites:
                    if (dealer == null)
                    {
                        this.appendSelectedNodesToDealerList(this.selectDealers("@type='dealer' or @type='branch'"), dealersToReport, calculationType == calculatorType.dealersAndSatellites);
                        this.appendCoordinatorAndAreas(dealersToReport);
                        this.appendSelectedNodesToDealerList("branch_total", dealersToReport);
                        this.appendSelectedNodesToDealerList("flop_total", dealersToReport);
                    }
                    else
                    {
                        switch (dealer.getTypeCode())
                        {
                            case "root":
                            case "area":
                            case "flop_total":
                                dealersToReport.AddRange(dealer.children);
                                break;
                            case "coordinator":
                            case "branch_total":
                                foreach (dealerDefinition definition in dealer.children)
                                {
                                    dealersToReport.Add(definition);
                                    if (calculationType == calculatorType.dealersAndSatellites)
                                    {
                                        dealersToReport.AddRange(definition.children);
                                    }
                                }
                                if (dealer.getTypeCode() == "coordinator")
                                {
                                    dealersToReport.Add(this.getRelatedDataCache().getDealer(dealer.getAttributeByName("parent")));
                                }
                                break;
                        }
                        if (dealer.getTypeCode() != "root")
                        {
                            dealersToReport.Add(dealer);
                        }
                    }
                    this.appendSelectedNodesToDealerList(calculationType.ToString() + "_total", dealersToReport);
                    this.appendSelectedNodesToDealerList("root", dealersToReport);
                    break;

                case calculatorType.connectedPoints:
                    this.appendSelectedNodesToDealerList("connected_point", dealersToReport);
                    this.appendSelectedNodesToDealerList("connectedPoints_total", dealersToReport);
                    this.appendSelectedNodesToDealerList("root", dealersToReport);
                    break;

                case calculatorType.network2:
                    this.appendSelectedNodesToDealerList("network2", dealersToReport);
                    this.appendSelectedNodesToDealerList("root", dealersToReport);
                    break;

                case calculatorType.network1:
                    this.appendSelectedNodesToDealerList("network1", dealersToReport);
                    this.appendSelectedNodesToDealerList("root", dealersToReport);
                    break;

                case calculatorType.allnetworks:
                    this.appendSelectedNodesToDealerList("network1", dealersToReport);
                    this.appendSelectedNodesToDealerList("network2", dealersToReport);
                    this.appendSelectedNodesToDealerList("root", dealersToReport);
                    break;
            }
            List<reportDealerInfo> list2 = new List<reportDealerInfo>();
            foreach (dealerDefinition definition in dealersToReport)
            {
                list2.Add(this.generateReportDataForSingleDealer(definition, calculationType, startMonth, endMonth));
            }
            list2.Sort(new reportDealerSorter());
            return list2.ToArray();
        }

        public cumulativeData generateReportDataForRootDealer(reportMonth startMonth, reportMonth endMonth)
        {
            List<dealerDefinition> dealersToReport = new List<dealerDefinition>();
            this.appendSelectedNodesToDealerList(this.selectDealers("@type='dealer' or @type='branch' or @type='satellite' or @type='connected_point' or @type='network1' or @type='network2'"), dealersToReport);
            cumulativeData data = new cumulativeData(this.getRelatedDataCache());
            foreach (dealerDefinition definition in dealersToReport)
            {
                data.appendCumulativeData(definition.getCumulativeData(startMonth, endMonth));
            }
            return data;
        }

        public reportDealerInfo generateReportDataForSingleDealer(dealerDefinition dealer, calculatorType calculationType, reportMonth startMonth, reportMonth endMonth)
        {
            return this.generateReportDataForSingleDealer(dealer, calculationType, startMonth, endMonth, false);
        }

        private reportDealerInfo generateReportDataForSingleDealer(dealerDefinition dealer, calculatorType calculationType, reportMonth startMonth, reportMonth endMonth, bool isRecursiveCall)
        {
            string key = this.getCacheStorageKey(dealer, calculationType, startMonth, endMonth, isRecursiveCall);
            bool flag = ConfigurationManager.AppSettings["cache_report_data"] == "1";
            if (!flag || (flag && !this.calculatedDataCache.ContainsKey(key)))
            {
                string str2 = dealer.getTypeCode();
                cumulativeData data = new cumulativeData(this.getRelatedDataCache());
                if ((str2 == "root") && (((calculationType != calculatorType.network1) && (calculationType != calculatorType.network2)) && (calculationType != calculatorType.allnetworks)))
                {
                    data = this.generateReportDataForRootDealer(startMonth, endMonth);
                }
                else
                {
                    if (((calculationType != calculatorType.dealersAndSatellites) || ((dealer.getTypeCode() != "branch") && (dealer.getTypeCode() != "dealer"))) || isRecursiveCall)
                    {
                        foreach (dealerDefinition definition in dealer.children)
                        {
                            if (((calculationType != calculatorType.network1) && (calculationType != calculatorType.network2)) || ((definition.children.Count > 0) || (definition.getTypeCode() == calculationType.ToString())))
                            {
                                data.appendCumulativeData(this.generateReportDataForSingleDealer(definition, calculationType, startMonth, endMonth, true).data);
                            }
                        }
                    }
                    data.appendCumulativeData(dealer.getCumulativeData(startMonth, endMonth));
                }
                if (!flag)
                {
                    return new reportDealerInfo(dealer, data);
                }
                this.calculatedDataCache.Add(key, new reportDealerInfo(dealer, data));
            }
            return this.calculatedDataCache[key];
        }

        private string getCacheStorageKey(dealerDefinition dealer, calculatorType calculationType, reportMonth startMonth, reportMonth endMonth, bool isRecursiveCall)
        {
            return string.Format("{0}/{1}/{2}/{3}/{4}", new object[] { dealer.getCode(), calculationType, Math.Min(startMonth.dateValue, endMonth.dateValue), Math.Max(startMonth.dateValue, endMonth.dateValue), isRecursiveCall });
        }

        public dealerDefinition[] getNonVirtualChildren(dealerDefinition parent)
        {
            List<dealerDefinition> nonVirtualChildren = new List<dealerDefinition>();
            this.appendNonVirtualChildren(parent, nonVirtualChildren);
            return nonVirtualChildren.ToArray();
        }

        public dataCache getRelatedDataCache()
        {
            return _relatedDataCache;
        }

        public static reportCalculator getReportCalculatorByProjectName(string projectName, string dataName)
        {
            return dataCache.getDataCacheByProjectName(projectName, dataName).reportCalculator;
        }

        private XmlNodeList selectDealers(string attributeQuery)
        {
            return this.getRelatedDataCache().xmlData.DocumentElement.SelectNodes("organization/dealer[" + attributeQuery + "]");
        }

        public dealerDefinition[] selectDealersByTypeCode(string typeCode)
        {
            List<dealerDefinition> dealersToReport = new List<dealerDefinition>();
            this.appendSelectedNodesToDealerList(typeCode, dealersToReport);
            return dealersToReport.ToArray();
        }
    }
}

